package com.wellness.commons.jwt;

import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;

/**
 * 分布式token生成，无需共享session，参考： <a>https://baijiahao.baidu.com/s?id=1608021814182894637&wfr=spider&for=pc</a>
 */
public class JwtUtils {

    /**
     * 设置有效期为 60 * 60 秒
     */
    private static final Long JWT_TTL = 3600000L;
    /**
     * 设置秘钥明文
     */
    private static final String JWT_KEY= "wellness";

    private static final String JWT_ISS = "cwgroup";

    /**
     * 创建toke
     * @param id            用户标识唯一id
     * @param subject       用户信息
     * @param ttlMillis     过期时间（ms）
     * @return
     */
    public static String generate(String id, String subject, Long ttlMillis){
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        if(ttlMillis == null){
            ttlMillis = JWT_TTL; //使用默认1h过期
        }
        long expMillis = nowMillis + ttlMillis;
        JwtBuilder builder = Jwts.builder()
                .setId(id)  //唯一的ID
                .setSubject(subject)   // 该JWT所面向的用户
//                .setAudience("aaa")  // 接收该JWT的一方，微服务本身
                .setIssuer(JWT_ISS)  // 签发者
                .setIssuedAt(new Date(nowMillis))  // 签发时间
//                .setNotBefore(new Date());   // 在此之前不可用
                .setExpiration(new Date(expMillis)) // 设置过期时间
                .signWith(signatureAlgorithm, generalKey()); //使用HS256对称加密算法签名, 第二个参数为秘钥;
        return builder.compact();
    }

    public static boolean isJwtValid(String jwt) {
        try {
            SecretKey secretKey = generalKey();
            //解析JWT字符串中的数据，并进行最基础的验证
            Claims claims = Jwts.parser()
                    .setSigningKey(secretKey)//SECRET_KEY是加密算法对应的密钥，jjwt可以自动判断机密算法
                    .parseClaimsJws(jwt)//jwt是JWT字符串
                    .getBody();
            String vaule = claims.getIssuer();//获取自定义字段key
            //判断自定义字段是否正确
            if (JWT_ISS.equals(vaule)) {
                return true;
            } else {
                return false;
            }
        }
        //在解析JWT字符串时，如果密钥不正确，将会解析失败，抛出SignatureException异常，说明该JWT字符串是伪造的
        //在解析JWT字符串时，如果‘过期时间字段’已经早于当前时间，将会抛出ExpiredJwtException异常，说明本次请求已经失效
        catch (SignatureException | ExpiredJwtException e) {
            return false;
        }
    }

    /**
     * 解析JWT
     * @param compactJwt  加密的token字符串
     */
    public static Claims parse(String  compactJwt) throws Exception{
        SecretKey secretKey = generalKey();
        Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(compactJwt).getBody();

        return claims;
    }

    /**
     * 生成加密后的秘钥 secretKey
     * @return
     */
    private static SecretKey generalKey() {
        byte[] encodedKey = Base64.encodeBase64(JWT_KEY.getBytes());
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    public static void main(String[] args) {
//        String  s = JwtUtils.generate("123456", "zhuo.shi", null); //10L
//        System.out.println(s);
//        try {
//            Thread.sleep(100L); //睡100L验证过期
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        boolean invalid = isJwtValid(s);
//        System.out.println(invalid);

        String a = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTYiLCJzdWIiOiJzaGl6aHVvIiwiaXNzIjoiY3dncm91cCIsImlhdCI6MTU4MzczMTk0OSwiZXhwIjoxNTgzNzM1NTQ5fQ.36OYVgzrPQgG6zYt72LnDV-I84uMj2jg23lmDmZCElc";
        String b = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTYiLCJzdWIiOiJ6aHVvLnNoaSIsImlzcyI6ImN3Z3JvdXAiLCJpYXQiOjE1ODM3MzIzMzEsImV4cCI6MTU4MzczNTkzMX0.GbjrSczcjlDsgvKrgD3KLO9zQ4sRqQy0eqvQVsxsTSo";
        String c = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJvWHhNTjBjazVUVkxpT3Vyb3FSdkFjM1kxb1VVIiwic3ViIjoiUHI2aWQvcklZT0hYcGJkeFM2SUlEQT09IiwiaXNzIjoiY3dncm91cCIsImlhdCI6MTU4NDU5NTczMiwiZXhwIjoxNTg0NjAyOTMyfQ.xiWhR_gJsDjtdYP0O7MhBlm86iNdMZrLUPA0KMpLvPQ";
        Claims claims = null;
        try {
            claims = JwtUtils.parse(c);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (claims != null) {
            String json = JSON.toJSONString(claims);
            System.out.println(json);
            System.out.println(claims.getNotBefore());
        }

    }
}
